package com.atguigu.paymentdemo.service.impl;

import com.atguigu.paymentdemo.config.WxPayConfig;
import com.atguigu.paymentdemo.entity.OrderInfo;
import com.atguigu.paymentdemo.entity.PaymentInfo;
import com.atguigu.paymentdemo.enums.OrderStatus;
import com.atguigu.paymentdemo.service.OrderInfoService;
import com.atguigu.paymentdemo.service.PaymentInfoService;
import com.atguigu.paymentdemo.service.RefundInfoService;
import com.atguigu.paymentdemo.util.OrderNoUtils;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.http.*;
import com.wechat.pay.java.core.http.okhttp.OkHttpClientAdapter;
import com.wechat.pay.java.core.notification.*;

import com.wechat.pay.java.core.util.IOUtil;
import com.wechat.pay.java.service.billdownload.BillDownloadService;
import com.wechat.pay.java.service.billdownload.model.BillType;
import com.wechat.pay.java.service.billdownload.model.GetTradeBillRequest;
import com.wechat.pay.java.service.billdownload.model.QueryBillEntity;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.*;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

@Service
@Slf4j
/** Native 支付下单为例 */
public class WxNavicateService {
    @Autowired
    private WxPayConfig wxPayConfig;
    @Autowired
    private  Config config;
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private PaymentInfoService paymentInfoService;
    @Autowired
    private NativePayService service;
    @Autowired
    private RefundService refundService;
    @Autowired
    private RefundInfoService refundInfoService;
    @Autowired
    private BillDownloadService billDownloadService;

    // /** 商户号 */
    // public static String merchantId = "190000****";
    // /** 商户API私钥路径 */
    // public static String privateKeyPath = "/Users/yourname/your/path/apiclient_key.pem";
    // /** 商户证书序列号 */
    // public static String merchantSerialNumber = "5157F09EFDC096DE15EBE81A47057A72********";
    // /** 商户APIV3密钥 */
    // public static String apiV3Key = "...";

    /**
     * native下单
     * @param orderInfo
     * @return
     */
    public  String order(OrderInfo orderInfo) {
        // // 使用微信支付公钥的RSA配置
        // Config config =
        //         new RSAPublicKeyConfig.Builder()
        //                 .merchantId(merchantId)
        //                 .privateKeyFromPath(privateKeyPath)
        //                 .publicKeyFromPath(publicKeyPath)
        //                 .publicKeyId(publicKeyId)
        //                 .merchantSerialNumber(merchantSerialNumber)
        //                 .apiV3Key(apiV3Key)
        //                 .build();

        // // 构建service
        // NativePayService service = new NativePayService.Builder().config(config).build();
        // request.setXxx(val)设置所需参数，具体参数可见Request定义
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(orderInfo.getTotalFee());
        request.setAmount(amount);
        request.setAppid(wxPayConfig.getAppid());
        request.setMchid(wxPayConfig.getMchId());
        request.setDescription("测试商品标题");
        request.setNotifyUrl(wxPayConfig.getNotifyDomain() + "/wechatpay/notify");
        request.setOutTradeNo(orderInfo.getOrderNo());
        // 调用下单方法，得到应答
        PrepayResponse response = service.prepay(request);
        // 使用微信扫描 code_url 对应的二维码，即可体验Native支付
        // System.out.println(response.getCodeUrl());
        return response.getCodeUrl();
    }

    /**
     * native下单回调通知
     * @param requestBody
     * @param wechatSignature
     * @param wechatPaySerial
     * @param wechatpayNonce
     * @param wechatTimestamp
     * @return
     */
    public ResponseEntity<String> handleWeChatPayNotification(String requestBody, String wechatSignature, String wechatPaySerial, String wechatpayNonce, String wechatTimestamp) {

        try {
            // Step 1: 构造 RequestParam
            RequestParam requestParam = new RequestParam.Builder()
                    .serialNumber(wechatPaySerial)
                    .nonce(wechatpayNonce)
                    .signature(wechatSignature)
                    .timestamp(wechatTimestamp)
                    .body(requestBody)
                    .build();

            // // Step 2: 初始化 NotificationConfig（这里以 RSAPublicKeyNotificationConfig 为例）
            // NotificationConfig config = new RSAPublicKeyNotificationConfig.Builder()
            //         .publicKeyFromPath(publicKeyPath)
            //         .publicKeyId(publicKeyId)
            //         .apiV3Key(apiV3Key)
            //         .build();

            // Step 3: 初始化 NotificationParser
            NotificationParser parser = new NotificationParser((NotificationConfig) config);

            // Step 4: 解析为 Transaction（支付回调）
            Transaction transaction = parser.parse(requestParam, Transaction.class);
            System.out.println("交易状态：" + transaction.getTradeState());
            System.out.println("订单号：" + transaction.getTransactionId());

            // Step 5: 执行业务逻辑（如更新订单状态等）
            if ("SUCCESS".equals(transaction.getTradeState().toString())) {
                // 处理成功
                System.out.println("支付成功，处理订单...");
                //  更新数据库、发送确认邮件等
                paymentInfoService.insertInfo(transaction);
                orderInfoService.updatePayStatusByOrderNo(transaction.getOutTradeNo(), OrderStatus.SUCCESS.getType());
            } else {
                System.out.println("交易未成功，状态：" + transaction.getTradeState());
            }

            return ResponseEntity.status(HttpStatus.OK).body("{\"code\": \"SUCCESS\", \"message\": \"OK\"}");

        } catch (Exception e) {
            e.printStackTrace();
            // 验签失败或解析失败
            if (e instanceof ValidationException) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("验签失败");
            }
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务器内部错误");
        }
    }


    /**
     * 根据内部订单号查询订单
     * @param outTradeNo 交易编号
     * @return {@link com.wechat.pay.java.service.payments.model.Transaction }
     */
    public  com.wechat.pay.java.service.payments.model.Transaction  queryOrderByOutOrderNo(String outTradeNo){
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(wxPayConfig.getMchId()); // 替换为你自己的商户号
        queryRequest.setOutTradeNo(outTradeNo);

        try {
            com.wechat.pay.java.service.payments.model.Transaction result = service.queryOrderByOutTradeNo(queryRequest);

            // 获取交易状态并打印
            String tradeState = result.getTradeState().toString();
            System.out.println("当前订单状态：" + tradeState);

            // 使用字符串比较（适用于 SDK v0.4.x 或 v0.5.x）
            if ("SUCCESS".equals(tradeState)) {
                System.out.println("订单支付成功！");
            } else if ("NOTPAY".equals(tradeState)) {
                System.out.println("订单未支付");
            } else if ("CLOSED".equals(tradeState)) {
                System.out.println("订单已关闭");
            } else {
                System.out.println("其他状态：" + tradeState);
            }

            return result;

        } catch (ServiceException e) {
            // API 返回失败，例如 ORDER_NOT_EXISTS、SYSTEM_ERROR 等
            System.err.printf("【微信支付查询失败】code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.err.printf("原始响应 body=[%s]\n", e.getResponseBody());

            // 可根据错误码做重试或其他处理
            if (Objects.equals("ORDER_NOT_EXISTS", e.getErrorCode())) {
                System.err.println("订单不存在，请检查 transactionId 是否正确");
            }

            throw e; // 或者返回 null / 自定义异常
        }
    }

    /**
     * 关闭订单
     *
     * @param outTradeNo 交易编号
     */
    public void closeOrder(String outTradeNo){
        CloseOrderRequest closeRequest = new CloseOrderRequest();
        closeRequest.setMchid(wxPayConfig.getMchId());
        closeRequest.setOutTradeNo(outTradeNo);
// 方法没有返回值，意味着成功时API返回204 No Content
        service.closeOrder(closeRequest);
    }

    /**
     * native退款
     * @param paymentInfo
     * @return
     */
    public  Refund refundOrder(PaymentInfo paymentInfo) {
        // // 使用微信支付公钥的RSA配置
        // Config config =
        //         new RSAPublicKeyConfig.Builder()
        //                 .merchantId(merchantId)
        //                 .privateKeyFromPath(privateKeyPath)
        //                 .publicKeyFromPath(publicKeyPath)
        //                 .publicKeyId(publicKeyId)
        //                 .merchantSerialNumber(merchantSerialNumber)
        //                 .apiV3Key(apiV3Key)
        //                 .build();

        // // 构建service
        // NativePayService service = new NativePayService.Builder().config(config).build();
        // request.setXxx(val)设置所需参数，具体参数可见Request定义
        CreateRequest request = new CreateRequest();
        AmountReq amountReq = new AmountReq();
        amountReq.setTotal(1l);
        amountReq.setRefund(1l);
        amountReq.setCurrency("CNY");
        request.setAmount(amountReq);
        request.setNotifyUrl(wxPayConfig.getNotifyDomain() + "/wechatpay/refund/notify");
        request.setOutTradeNo(paymentInfo.getOrderNo());
        request.setReason("正常退款");
        // request.setFundsAccount();
        request.setOutRefundNo(OrderNoUtils.getRefundNo());
        // request.setSubMchid();
        request.setTransactionId(paymentInfo.getTransactionId());
        // 调用退款方法，得到应答
        Refund refund = refundService.create(request);

        return refund;
    }

    /**
     * native退款回调通知
     * @return
     */
    public  ResponseEntity handleWeChatRefundNotification(String requestBody, String wechatSignature, String wechatPaySerial, String wechatpayNonce, String wechatTimestamp) {
        try {
            // Step 1: 构造 RequestParam
            RequestParam requestParam = new RequestParam.Builder()
                    .serialNumber(wechatPaySerial)
                    .nonce(wechatpayNonce)
                    .signature(wechatSignature)
                    .timestamp(wechatTimestamp)
                    .body(requestBody)
                    .build();

            // Step 2: 初始化 NotificationParser
            NotificationParser parser = new NotificationParser((NotificationConfig) config);

            // Step 3: 解析为 RefundNotification（注意：不是 Transaction）
            RefundNotification refundNotification = parser.parse(requestParam, RefundNotification.class);

            // Step 4: 获取关键信息
            String outTradeNo = refundNotification.getOutTradeNo();       // 商户订单号
            String outRefundNo = refundNotification.getOutRefundNo();     // 商户退款单号
            String refundId = refundNotification.getRefundId();           // 微信退款单号
            Status refundStatus = refundNotification.getRefundStatus();// 退款状态

            System.out.println("收到退款通知");
            System.out.println("商户订单号：" + outTradeNo);
            System.out.println("商户退款单号：" + outRefundNo);
            System.out.println("微信退款单号：" + refundId);
            System.out.println("退款状态：" + refundStatus);

            // Step 5: 根据退款状态执行业务逻辑
            if (Status.SUCCESS.equals(refundStatus)) {
                System.out.println("退款成功，更新订单状态...");
                // 执行业务操作：更新数据库、发送短信、记录日志等
                refundInfoService.insertByInfo(refundNotification);
                paymentInfoService.updatePayStatusByOrderNo(outTradeNo,OrderStatus.REFUND_SUCCESS.getType());
                orderInfoService.updatePayStatusByOrderNo(outTradeNo,OrderStatus.REFUND_SUCCESS.getType());
            } else if (Status.CLOSED.equals(refundStatus)) {
                System.out.println("退款已关闭");
                // 可记录异常或触发人工审核
            } else if (Status.PROCESSING.equals(refundStatus)) {
                System.out.println("退款处理中，暂不处理");
            } else {
                orderInfoService.updatePayStatusByOrderNo(outTradeNo,OrderStatus.REFUND_ABNORMAL.getType());
                System.out.println("未知退款状态：" + refundStatus);
            }

            // Step 6: 返回 SUCCESS 响应给微信服务器，防止重复通知
            return ResponseEntity.ok("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");

        } catch (Exception e) {
            e.printStackTrace();
            // 出现异常时返回失败响应，微信会重试
            return ResponseEntity.status(500).body("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[ERROR]]></return_msg></xml>");
        }
    }


    /**
     * native申请交易账单
     * @param billate
     * @return
     */
    public  String applTradeText(String billate) {

        // 创建请求对象

        GetTradeBillRequest request = new GetTradeBillRequest();
        request.setBillDate(String.valueOf(billate));
        request.setBillType(BillType.ALL);
        QueryBillEntity tradeBill = billDownloadService.getTradeBill(request);
        return tradeBill.getDownloadUrl();
    }

    /**
     * native下载交易账单
     * @param downloadUrl
     * @return
     */
    public  String downloadTradeText(String downloadUrl) throws IOException {
        AbstractHttpClient httpClient = new DefaultHttpClientBuilder().config(config).build();

        InputStream inputStream = httpClient.download(downloadUrl);

        // 非压缩的账单可使用 core.util.IOUtil 从流读入内存字符串，大账单请慎用
        String respBody = IOUtil.toString(inputStream);
        inputStream.close();
        return respBody;
    }

}
